package com.greenline.push.core.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public abstract class AbstractLocalCache<K extends Object, T extends Object> {

    protected final Map<K, T> data = new HashMap<K, T>();

    protected final ReadWriteLock lock = new ReentrantReadWriteLock();

    protected long updateTime = 0L;

    // 更新间隔10分钟
    protected long updateInterval = 10 * 60 * 1000000000L;

    protected void setUpdateInterval(long updateInterval) {
        this.updateInterval = updateInterval;
    }

    protected void checkReload() {
        long nona = System.nanoTime();
        if (nona - updateTime > updateInterval || data.isEmpty()) {
            load();
        }
    }

    /**
     * 生成key
     * 
     * @param t
     * @return
     */
    protected abstract K getkey(T t);

    /**
     * 取得所有需要放入map里的数据
     * 
     * @return
     */
    protected abstract List<T> listData();
    
    /**
     * 查询数据库
     * @param k
     * @return
     */
    protected abstract T getDatebase(K k);

    /**
     * @param k
     * @return 取得缓存map里的数据
     * @throws PayException
     */
    protected T get(K k) {
        checkReload();
        T t = null;
        lock.readLock().lock();
        try {
            t = data.get(k);
        } finally {
            lock.readLock().unlock();
        }
        if(null == t){
        	t = this.getDatebase(k);
        }
        return t;
    }

    /**
     * 重新加载数据
     */
    protected void load() {
        lock.writeLock().lock();
        try {
            List<T> list = listData();
            data.clear();
            if (list != null) {
                for (T t : list) {
                    data.put(getkey(t), t);
                }
            }
        } finally {
            updateTime = System.nanoTime();
            lock.writeLock().unlock();
        }
    }

    /**
     * @return
     */
    protected List<T> listCacheData() {
        checkReload();
        List<T> list = new ArrayList<T>();
        lock.readLock().lock();
        try {
            for (T t : data.values()) {
                if (!list.contains(t)) {
                    list.add(t);
                }
            }
        } finally {
            lock.readLock().unlock();
        }
        return list;
    }
}
